﻿using System;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using JTLeigh.Commerce.Spencer.Core.Testing;
using JTLeigh.Commerce.Spencer.Core.Testing.Mocks.Data;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Common.Entities;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Data.Providers;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Commerce.Spencer.Features.ProductImages.Data.UnitTests.Providers
{

	/// <summary>
	/// Unit tests for the <see cref="ProductImageMetadataProvider"/> class.
	/// </summary>
	[TestClass]
	public class ProductImageMetadataProviderFixture
	{

		#region Inner Classes and Types

		private static class Constants
		{

			public static class ProductImageSize
			{

				public static class SizeId
				{
					public static readonly Guid Thumbnail = new Guid("176CE418-6309-4d9f-928C-8CFE344D40A8");
					public static readonly Guid Small = new Guid("E60FF2A3-3EC7-44d6-913F-4FB6BD9FDDE1");
				}

			}

			public static class ProductImageView
			{

				public static class ViewId
				{
					public static readonly Guid Front = new Guid("32583D4F-673D-4a7b-BDEA-4FA444264B92");
					public static readonly Guid Left = new Guid("8A282AC2-195A-4962-87EE-318960F731A2");
				}

			}

		}

		private static class StoredProcedure
		{

			public static class GetProductImageMetadata
			{

				public static class Table
				{

					public static readonly DataTable ProductImageSize;
					public static readonly DataTable ProductImageSizeLocalization;
					public static readonly DataTable ProductImageView;
					public static readonly DataTable ProductImageViewLocalization;

					[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Reviewed.")]
					static Table()
					{
						ProductImageSize = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.SizeId, typeof(Guid)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.WellKnownSizeCode, typeof(byte)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.Width, typeof(short)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.Height, typeof(short)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.DisplayOrder, typeof(int)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.DefaultName, typeof(string)));
						ProductImageSize.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.DefaultMissingImagePath, typeof(string)));

						ProductImageSizeLocalization = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageSizeLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSize.SizeId, typeof(Guid)));
						ProductImageSizeLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSizeLocalization.CultureId, typeof(int)));
						ProductImageSizeLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSizeLocalization.Name, typeof(string)));
						ProductImageSizeLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageSizeLocalization.MissingImagePath, typeof(string)));

						ProductImageView = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageView.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageView.ViewId, typeof(Guid)));
						ProductImageView.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageView.WellKnownViewCode, typeof(byte)));
						ProductImageView.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageView.DisplayOrder, typeof(int)));
						ProductImageView.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageView.DefaultName, typeof(string)));

						ProductImageViewLocalization = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageViewLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageView.ViewId, typeof(Guid)));
						ProductImageViewLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageViewLocalization.CultureId, typeof(int)));
						ProductImageViewLocalization.Columns.Add(new DataColumn(ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.ColumnName.ProductImageViewLocalization.Name, typeof(string)));
					}

				}

			}

		}

		#endregion // Inner Classes and Types

		#region Methods

		#region GetProductImageMetadata

		/// <summary>
		/// Ensures <see cref="ProductImageMetadataProvider.GetProductImageMetadata"/> gets product 
		/// image metadata from the database.
		/// </summary>
		[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Reviewed.")]
		[TestMethod]
		public void TestGetProductImageMetadata()
		{
			DataTable sizeResults;
			DataTable sizeLocalizationResults;
			DataTable viewResults;
			DataTable viewLocalizationResults;
			DataTable[] results;
			DataTableReader reader;
			MockDatabaseCommandExecuteReaderReturns command;
			MockDatabaseConnection connection;
			MockDatabaseConnectionFactory connectionFactory;
			ProductImageMetadataProvider provider;
			ProductImageMetadata metadata;
			ProductImageSize sizeA;
			ProductImageSize sizeB;
			ProductImageSizeLocalization sizeLocalization;
			ProductImageView viewA;
			ProductImageView viewB;
			ProductImageViewLocalization viewLocalization;

			sizeResults = StoredProcedure.GetProductImageMetadata.Table.ProductImageSize.Clone();
			sizeResults.Rows.Add(Constants.ProductImageSize.SizeId.Thumbnail, 1, 50, 75, 10, "Size 1 Default Name", "Size 1 Default Missing Image Path");
			sizeResults.Rows.Add(Constants.ProductImageSize.SizeId.Small, 2, 100, 150, 20, "Size 2 Default Name", "Size 2 Default Missing Image Path");

			sizeLocalizationResults = StoredProcedure.GetProductImageMetadata.Table.ProductImageSizeLocalization.Clone();
			sizeLocalizationResults.Rows.Add(Constants.ProductImageSize.SizeId.Thumbnail, TestConstants.CultureId.EnglishCanada, "Thumbnail View English Name", "/path/to/missing/thumbnail/image/english.gif");
			sizeLocalizationResults.Rows.Add(Constants.ProductImageSize.SizeId.Thumbnail, TestConstants.CultureId.FrenchCanada, "Thumbnail View French Name", "/path/to/missing/thumbnail/image/french.gif");
			sizeLocalizationResults.Rows.Add(Constants.ProductImageSize.SizeId.Small, TestConstants.CultureId.EnglishCanada, "Small View English Name", "/path/to/missing/small/image/english.gif");
			sizeLocalizationResults.Rows.Add(Constants.ProductImageSize.SizeId.Small, TestConstants.CultureId.FrenchCanada, "Small View French Name", "/path/to/missing/small/image/french.gif");

			viewResults = StoredProcedure.GetProductImageMetadata.Table.ProductImageView.Clone();
			viewResults.Rows.Add(Constants.ProductImageView.ViewId.Front, 1, 10, "View 1 Default Name");
			viewResults.Rows.Add(Constants.ProductImageView.ViewId.Left, 2, 20, "View 2 Default Name");

			viewLocalizationResults = StoredProcedure.GetProductImageMetadata.Table.ProductImageViewLocalization.Clone();
			viewLocalizationResults.Rows.Add(Constants.ProductImageView.ViewId.Front, TestConstants.CultureId.EnglishCanada, "Front View English Name");
			viewLocalizationResults.Rows.Add(Constants.ProductImageView.ViewId.Front, TestConstants.CultureId.FrenchCanada, "Front View French Name");
			viewLocalizationResults.Rows.Add(Constants.ProductImageView.ViewId.Left, TestConstants.CultureId.EnglishCanada, "Left View English Name");
			viewLocalizationResults.Rows.Add(Constants.ProductImageView.ViewId.Left, TestConstants.CultureId.FrenchCanada, "Left View French Name");

			results = new DataTable[]
			{
				sizeResults,
				sizeLocalizationResults,
				viewResults,
				viewLocalizationResults,
			};

			reader = new DataTableReader(results);

			command = new MockDatabaseCommandExecuteReaderReturns(ProductImageMetadataProvider.DatabaseSchema, ProductImageMetadataProvider.StoredProcedure.GetProductImageMetadata.CommandName, 1, reader);

			connection = new MockDatabaseConnection(command.Object);

			connectionFactory = new MockDatabaseConnectionFactory(TestConstants.TenantId.JTLeigh, ProductImageMetadataProvider.DatabaseKeyReadOperations, connection.Object);

			provider = new ProductImageMetadataProvider()
			{
				DatabaseConnectionFactory = connectionFactory.Object,
			};

			metadata = provider.GetProductImageMetadata(TestConstants.TenantId.JTLeigh);

			command.VerifyAll();
			connection.VerifyAll();

			Assert.IsNotNull(metadata);

			Assert.AreEqual(2, metadata.SizesByWellKnowSizeCode.Count);
			Assert.AreEqual(2, metadata.SizesBySizeId.Count);

			Assert.IsTrue(metadata.SizesByWellKnowSizeCode.TryGetValue(1, out sizeA));
			Assert.IsTrue(metadata.SizesBySizeId.TryGetValue(Constants.ProductImageSize.SizeId.Thumbnail, out sizeB));
			Assert.AreSame(sizeA, sizeB);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Thumbnail, sizeA.SizeId);
			Assert.AreEqual((byte)1, sizeA.WellKnownSizeCode);
            Assert.AreEqual(50, sizeA.Width);
            Assert.AreEqual(75, sizeA.Height);
			Assert.AreEqual(10, sizeA.DisplayOrder);
			Assert.AreEqual("Size 1 Default Name", sizeA.DefaultName);
			Assert.AreEqual("Size 1 Default Missing Image Path", sizeA.DefaultMissingImagePath);
			Assert.AreEqual(2, sizeA.Localizations.Count);
			Assert.IsTrue(sizeA.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out sizeLocalization));
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Thumbnail, sizeLocalization.SizeId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, sizeLocalization.CultureId);
			Assert.AreEqual("Thumbnail View English Name", sizeLocalization.Name);
			Assert.AreEqual("/path/to/missing/thumbnail/image/english.gif", sizeLocalization.MissingImagePath);
			Assert.IsTrue(sizeA.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out sizeLocalization));
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Thumbnail, sizeLocalization.SizeId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, sizeLocalization.CultureId);
			Assert.AreEqual("Thumbnail View French Name", sizeLocalization.Name);
			Assert.AreEqual("/path/to/missing/thumbnail/image/french.gif", sizeLocalization.MissingImagePath);

			Assert.IsTrue(metadata.SizesByWellKnowSizeCode.TryGetValue(2, out sizeA));
			Assert.IsTrue(metadata.SizesBySizeId.TryGetValue(Constants.ProductImageSize.SizeId.Small, out sizeB));
			Assert.AreSame(sizeA, sizeB);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Small, sizeA.SizeId);
			Assert.AreEqual((byte)2, sizeA.WellKnownSizeCode);
			Assert.AreEqual(100, sizeA.Width);
            Assert.AreEqual(150, sizeA.Height);
			Assert.AreEqual(20, sizeA.DisplayOrder);
			Assert.AreEqual("Size 2 Default Name", sizeA.DefaultName);
			Assert.AreEqual("Size 2 Default Missing Image Path", sizeA.DefaultMissingImagePath);
			Assert.AreEqual(2, sizeA.Localizations.Count);
			Assert.IsTrue(sizeA.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out sizeLocalization));
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Small, sizeLocalization.SizeId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, sizeLocalization.CultureId);
			Assert.AreEqual("Small View English Name", sizeLocalization.Name);
			Assert.AreEqual("/path/to/missing/small/image/english.gif", sizeLocalization.MissingImagePath);
			Assert.IsTrue(sizeA.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out sizeLocalization));
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Small, sizeLocalization.SizeId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, sizeLocalization.CultureId);
			Assert.AreEqual("Small View French Name", sizeLocalization.Name);
			Assert.AreEqual("/path/to/missing/small/image/french.gif", sizeLocalization.MissingImagePath);

			Assert.AreEqual(2, metadata.ViewsByWellKnowViewCode.Count);
			Assert.AreEqual(2, metadata.ViewsByViewId.Count);

			Assert.IsTrue(metadata.ViewsByWellKnowViewCode.TryGetValue(1, out viewA));
			Assert.IsTrue(metadata.ViewsByViewId.TryGetValue(Constants.ProductImageView.ViewId.Front, out viewB));
			Assert.AreSame(viewA, viewB);
			Assert.AreEqual(Constants.ProductImageView.ViewId.Front, viewA.ViewId);
			Assert.AreEqual((byte)1, viewA.WellKnownViewCode);
			Assert.AreEqual(10, viewA.DisplayOrder);
			Assert.AreEqual("View 1 Default Name", viewA.DefaultName);
			Assert.AreEqual(2, viewA.Localizations.Count);
			Assert.IsTrue(viewA.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out viewLocalization));
			Assert.AreEqual(Constants.ProductImageView.ViewId.Front, viewLocalization.ViewId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, viewLocalization.CultureId);
			Assert.AreEqual("Front View English Name", viewLocalization.Name);
			Assert.IsTrue(viewA.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out viewLocalization));
			Assert.AreEqual(Constants.ProductImageView.ViewId.Front, viewLocalization.ViewId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, viewLocalization.CultureId);
			Assert.AreEqual("Front View French Name", viewLocalization.Name);

			Assert.IsTrue(metadata.ViewsByWellKnowViewCode.TryGetValue(2, out viewA));
			Assert.IsTrue(metadata.ViewsByViewId.TryGetValue(Constants.ProductImageView.ViewId.Left, out viewB));
			Assert.AreSame(viewA, viewB);
			Assert.AreEqual(Constants.ProductImageView.ViewId.Left, viewA.ViewId);
			Assert.AreEqual((byte)2, viewA.WellKnownViewCode);
			Assert.AreEqual(20, viewA.DisplayOrder);
			Assert.AreEqual("View 2 Default Name", viewA.DefaultName);
			Assert.AreEqual(2, viewA.Localizations.Count);
			Assert.IsTrue(viewA.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out viewLocalization));
			Assert.AreEqual(Constants.ProductImageView.ViewId.Left, viewLocalization.ViewId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, viewLocalization.CultureId);
			Assert.AreEqual("Left View English Name", viewLocalization.Name);
			Assert.IsTrue(viewA.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out viewLocalization));
			Assert.AreEqual(Constants.ProductImageView.ViewId.Left, viewLocalization.ViewId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, viewLocalization.CultureId);
			Assert.AreEqual("Left View French Name", viewLocalization.Name);
		}

		#endregion // GetProductImageMetadata

		#endregion // Methods

	}

}
